#pragma once
#include "TcpServer.hpp"
#include "util.hpp"
#include <unordered_map>

using namespace socket_module;

const std::string space = " ";
const std::string header_gap = ": ";
const std::string next_line = "\r\n";
const std::string home_page = "./wwwhome";
const std::string default_page = "index.html";
// 请求对象
class requestMsg
{
public:
    requestMsg() {}
    ~requestMsg() {}

public:
    void serialize() {}
    void deserialize(std::string msg)
    {
        std::string request_line = util::readOneLine(msg, next_line);
        parseRequestLine(request_line);
        std::cout << _method << _uri << _version << std::endl;
        // 根据传过来的uri判断用户想访问的文件位置
        std::cout << "_uri is " << _uri << std::endl;
        if (_uri == "/")
        {
            _uri = home_page + _uri + default_page;
        }
        else
        {
            _uri = home_page + _uri;
        }
        std::cout << "_uri is " << _uri << std::endl;
    }
    std::string uri()
    {
        return _uri;
    }
    void parseRequestLine(std::string requestLine)
    {
        std::stringstream ss(requestLine);
        ss >> _method >> _uri >> _version; // 这个流写入时会根据空格判断是否要输入多个 就跟我们使用scanf一样
    }

private:
    std::string _method;
    std::string _uri;
    std::string _version;
    std::unordered_map<std::string, std::string> _request_header;
    std::string _text;
};
class responseMsg
{
public:
    responseMsg()
        : _blankLine(next_line),
          _version("HTTP/1.1"),
          _code(200),
          _des_code("OK")
    {
    }

public:
    std::string serialize()
    {
        std::stringstream ret;

        set_header("Content-Length", std::to_string(util::fileSize(_target_file)));
        _rsp_header["Content-Type"] = "text/html";
        // 状态行
        ret << _version << space << _code << space << _des_code << next_line;
        // 判断是否是重定向
        if (_code == 301)
        {
            // 重定向只发送 Location 和空行
            for (auto &x : _rsp_header)
            {
                ret << x.first << header_gap << x.second << next_line;
            }
            ret << _blankLine; // 结束响应头
            return ret.str();
        }
        // 响应报头行
        for (auto &x : _rsp_header)
        {
            ret << x.first << header_gap << x.second << next_line;
        }
        // 空行
        ret << _blankLine;
        ret << _text;
        std::cout << "_ret is " << ret.str() << std::endl;
        return ret.str();
    }
    void deserialize() {}

public:
    // 设置头部的函数
    void set_header(std::string key, std::string value)
    {
        // 先查找是否已经有了头部
        if (_rsp_header.find(key) == _rsp_header.end())
            _rsp_header[key] = value;
        return;
    }
    // 识别信息类型
    std::string set_type()
    {
        size_t pos = _target_file.find_last_of(".");
        if (pos = std::string::npos)
            return "text/html";
        std::string suffix = _target_file.substr(pos);
        if (suffix == ".jpg" || ".jpeg")
            return "image/jpeg";
        else if (suffix == ".png")
            return "image/png";
        else if (suffix == ".ico")
            return "image/x-icon";
    }
    void set_target_file(std::string target_file)
    {
        std::cout << "target_file is" << target_file << std::endl;
        _target_file = target_file;
    }
    void set_code(int code)
    {
        _code = code;
        switch (_code)
        {
        case 301:
            _des_code = "Moved Permanently";
            break;
        }
    }
    void redirect()
    {
        set_header("Location", "https://www.baidu.com/");
        set_code(301);
    }
    void make_response()
    {
        _text = util::readFile(_target_file);
    }

private:
    std::string _version;
    int _code;
    std::string _des_code;
    std::unordered_map<std::string, std::string> _rsp_header;
    std::string _target_file;
    std::string _text;
    std::string _blankLine;
};
class HttpServer
{
public:
    HttpServer(uint16_t port)
        : _tcp(std::make_shared<TcpServer>(port))
    {
    }

public:
    void HandlerHttpRequest(Socket::ptr &sock, InetAddr &inet)
    {
        requestMsg req;
        std::string msg;
        sock->Recv(&msg);
        req.deserialize(msg);
        responseMsg rsp;
        rsp.set_target_file(req.uri());
        rsp.make_response();
        rsp.redirect();
        std::string ret = rsp.serialize();
        sock->Send(ret);
    }
    void Start()
    {
        _tcp->Start([this](Socket::ptr &sock, InetAddr &inet)
                    { this->HandlerHttpRequest(sock, inet); });
    }

private:
    TcpServer::ptr _tcp;
};